﻿using System;
using System.Linq;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using System.Transactions;
using Newtonsoft.Json;
using T.FAS.Runtime.DataModel.Dao;
using T.FAS.Runtime.Metadata.Entity.DataModel;
using T.ServiceComponent.DAC.Service;
using System.Reflection;
using System.Data;
using T.FAS.Runtime.Base.Entity;
using T.FAS.Runtime.Base.Dao;

namespace T.FAS.Runtime.DataModel.Dao
{
    /// <summary>
    /// DataObject ELB Dao,跟SDO共用
    /// </summary>
    public class DataObjectELBDao : DaoService<DataObject>, IDataObjectDao
    {
        #region Fields & Properties
        public const string MetaDataID = DataModelConst.DOMetaType;
        public const string MetaDataName = "数据对象"; 
        public override string TableName => "FAS_DataObject";
        public override string IDColumnName => "ID";
        public override List<string> ExceptColumnName { get; } =
                DaoUtil.GetExceptionColumn<DataObject>()
                        .Concat(new List<string> {
                            "ActualTableNames",
                            "TableShardingStrategyID",
                            EntityTools.ProjectBranchID,
                        })
                        .ToList();
        private readonly DataColumnELBDao _dataColumnELBDao = new DataColumnELBDao();
        private readonly DataObjectIndexELBDao _dataObjectIndexELBDao = new DataObjectIndexELBDao();
        private readonly DataObjectIndexColumnELBDao _dataObjectIndexColumnELBDao = new DataObjectIndexColumnELBDao();
        private readonly DataObjectRelationELBDao _dataObjectRelationELBDao = new DataObjectRelationELBDao();
        private readonly StaticDataObjectPresetDataELBDao _staticDataObjectPresetDataELBDao = new StaticDataObjectPresetDataELBDao();
        private readonly DatabaseELBDao _databaseELBDao = new DatabaseELBDao();
        private readonly DataObjectColumnHelpSettingELBDao _dataObjectColumnHelpSettingELBDao = new DataObjectColumnHelpSettingELBDao();

        #endregion

        public DataObjectELBDao() : base()
        {
            DBName = "TFAS";
        }

        public override Dictionary<string, PropertyInfo> GetColumns()
        {
            return DaoServiceExtension.GetAllColumns<DataObject>(base.GetColumns());
        }

        #region 获取
        /// <summary>
        /// 根据ID获取DO
        /// </summary>
        /// <param name="doId"></param>
        /// <returns></returns>
        public DataObject GetDataObjectByID(string doId)
        {
            return GetDataObjectByID(doId, false);
        }

        /// <summary>
        /// 根据Code获取DO
        /// </summary>
        /// <param name="metaDataId"></param>
        /// <returns></returns>
        public DataObject GetDataObjectByCode(string doCode)
        {
            if (string.IsNullOrEmpty(doCode))
            {
                return default;
            }
            var data = base.GetObjectsByFilter($"Code='{doCode}'")?.FirstOrDefault() as DataObject;
            InitializeDO(data);
            return data;
        }

        public List<DataObjectIndex> GetDataObjectIndexsByDataObjectID(Dictionary<string, string> filter)
        {
            return _dataObjectIndexELBDao.GetDataObjectIndexs(filter["ID"]);
        }

        /// <summary>
        /// 获取元数据内容
        /// </summary>
        /// <param name="metaDataId"></param>
        /// <returns></returns>
        public List<DataObject> GetDataObjects(Dictionary<string, string> filter)
        {
            var result = new List<DataObject>();
            if (filter == null)
            {
                return result;
            }
            List<object> objects = base.GetObjectsByFilter("1=1");
            if (objects != null)
            {
                objects.ForEach(obj => result.Add(obj as DataObject));
            }
            result.ForEach(dao => {
                dao.Columns = _dataColumnELBDao.GetDataColumns(dao.ID);
                dao.DataObjectIndexs = _dataObjectIndexELBDao.GetDataObjectIndexs(dao.ID);
                dao.DataObjectRelations = _dataObjectRelationELBDao.GetDataObjectRelations(dao.ID);
                dao.Database = _databaseELBDao.GetDatabaseByID(dao.DatabaseID);
                dao.PresetData = _staticDataObjectPresetDataELBDao.GetStaticDataObjectPresetDatas(dao.ID);
                dao.ColumnHelpSettings = _dataObjectColumnHelpSettingELBDao.GetColumnHelpSettings(dao.ID);
                DealFKColumn(dao);
            });
            return result;
        }
        #endregion

        #region 新增

        public void SaveDataObject(DataObject dataObject)
        {
            try
            {
                using (var scope = new TransactionScope(TransactionScopeOption.Required, new TransactionOptions(){IsolationLevel = System.Transactions.IsolationLevel.ReadCommitted}))
                {
                    base.Add(new List<object> { dataObject });
                    scope.Complete();
                }
            }
            catch (Exception e)
            {
                throw new FasException(DataModelErrorCode.DO.CreateError, e.Message, e);
            }
        }

        public void SaveDataObjectIndexs(List<DataObjectIndex> dataObjectIndexs)
        {
            _dataObjectIndexELBDao.CreateDataObjectIndex(dataObjectIndexs);
        }

        public void SaveDataObjectIndexColumns(List<DataObjectIndexColumn> dataObjectIndexColumns)
        {
            _dataObjectIndexColumnELBDao.CreateDataObjectIndexColumn(dataObjectIndexColumns);
        }
        #endregion

        #region 删除
        /// <summary>
        /// 删除DataObject
        /// </summary>
        /// <param name="DataObjects"></param>
        public void DeleteDataObject(string doId)
        {
            try
            {
                base.Delete(new List<string> { doId });
            }
            catch (Exception e)
            {
                throw new FasException(DataModelErrorCode.DO.DeleteError, e.Message, e);
            }
        }

        public void DeleteDataObject(Dictionary<string, string> filter)
        {
            try
            {
                var id = filter["ID"];
                DeleteDataObject(id);
            }
            catch (Exception e)
            {
                throw new FasException(DataModelErrorCode.DO.DeleteError, e.Message, e);
            }
        }
        #endregion

        #region 修改
        public void UpdateDataObject(DataObject dataObject)
        {
            try
            {
                using (var scope = new TransactionScope(TransactionScopeOption.Required, new TransactionOptions(){IsolationLevel = System.Transactions.IsolationLevel.ReadCommitted}))
                {
                    DeleteDataObject(dataObject.ID);
                    SaveDataObject(dataObject);
                }
            }
            catch (Exception e)
            {
                throw new FasException(DataModelErrorCode.DO.UpdateError, e.Message, e);
            }
        }
        #endregion

        #region Private Funcs
        /// <summary>
        /// 通过ID获取DO元数据
        /// </summary>
        /// <param name="doId"></param>
        /// <param name="flag"></param>
        /// <returns></returns>
        private DataObject GetDataObjectByID(string doId, bool flag = false)
        {
            var dataobject = base.GetObject(doId);
            if (dataobject == null)
                return null;
            InitializeDO(dataobject);
            if (!flag)   //避免A->B->C->A套圈引用内存溢出的bug
                DealFKColumn(dataobject);
            return dataobject;
        }

        /// <summary>
        /// 处理外键列，给Column填充DO引用
        /// </summary>
        /// <param name="dataObject"></param>
        private void DealFKColumn(DataObject dataObject)
        {
            foreach (var col in dataObject.Columns)
            {
                if (col.IsFkColumn)
                {
                    //自关联，引用取自身
                    if (string.Equals(col.RelatedDataObjectID, col.DataObjectID))
                        col.RelatedDataObjectPrimaryKey = dataObject?.Columns.Find(o => o.IsPkColumn);
                    else
                    {
                        col.RelatedDataObjectPrimaryKey = GetDataObjectByID(col.RelatedDataObjectID, true)?.Columns.Find(o => o.IsPkColumn);
                    }
                }
            }
        }

        /// <summary>
        /// 填充DO内容
        /// </summary>
        /// <param name="dataObject"></param>
        private void InitializeDO(DataObject dataObject)
        {
            if (dataObject == null)
                return;
            dataObject.Columns = _dataColumnELBDao.GetDataColumns(dataObject.ID)?.OrderBy(col => col.ColumnOrder).ToList();
            dataObject.DataObjectRelations = _dataObjectRelationELBDao.GetDataObjectRelations(dataObject.ID);
            dataObject.ColumnHelpSettings = _dataObjectColumnHelpSettingELBDao.GetColumnHelpSettings(dataObject.ID);
            dataObject.PresetData = _staticDataObjectPresetDataELBDao.GetStaticDataObjectPresetDatas(dataObject.ID);
            dataObject.DataObjectIndexs = _dataObjectIndexELBDao.GetDataObjectIndexs(dataObject.ID);
            //优化获取索引的列信息
            var indexColumns = _dataObjectIndexColumnELBDao.GetDataObjectIndexColumnsByMetaDataForeignKey(dataObject.ID);
            foreach (var index in dataObject.DataObjectIndexs)
            {
                index.Columns = indexColumns.Where(col => col.IndexID == index.ID && col.ColumnIndexType == 0).ToList();
                index.IncludeColumns = indexColumns.Where(col => col.IndexID == index.ID && col.ColumnIndexType == 1).ToList();
            }
            //dataobject.Database = DatabaseELBDao.GetDatabaseByID(dataobject.DatabaseID);
        }

        #endregion
    }
}
